home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / mac / imfapp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  43.6 KB  |  1,771 lines  |  [TEXT/R*ch]

  1. /* Program that translates and previews image families for Mac Xconq.
  2.    Copyright (C) 1992, 1993, 1994, 1995 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. /* This is a simple app whose function is to translate and preview
  10.    Xconq images and image families. */
  11.  
  12. #include "config.h"
  13. #include "misc.h"
  14. void prealloc_debug(void);
  15. #include "lisp.h"
  16. #include "imf.h"
  17.  
  18. #ifdef THINK_C
  19. #include <MacHeaders>
  20. #else /* probably MPW */
  21. #include <Types.h>
  22. #include <Memory.h>
  23. #include <Resources.h>
  24. #include <QuickDraw.h>
  25. #include <Values.h>
  26. #include <Fonts.h>
  27. #include <Events.h>
  28. #include <Windows.h>
  29. #include <Menus.h>
  30. #include <Dialogs.h>
  31. #include <Desk.h>
  32. #include <ToolUtils.h>
  33. #include <SegLoad.h>
  34. #include <Files.h>
  35. #include <Folders.h>
  36. #include <OSUtils.h>
  37. #include <OSEvents.h>
  38. #include <DiskInit.h>
  39. #include <Packages.h>
  40. #include <Traps.h>
  41. #include <StandardFile.h>
  42. #endif
  43.  
  44. #include "macimf.h"
  45.  
  46. #ifdef MPW
  47. #define QD(whatever) (qd.##whatever)
  48. #define QDPat(whatever) (&(qd.##whatever))
  49. #endif
  50. #ifdef THINK_C
  51. #define QD(whatever) (whatever)
  52. #define QDPat(whatever) (whatever)
  53. #endif
  54.  
  55. /* Definitions for the menus. */
  56.  
  57. #define mbMain 128
  58.  
  59. #define mApple 128
  60.  
  61. #define miAbout 1
  62.  
  63. #define mFile 129
  64.  
  65. #define miFileNew 1
  66. #define miFileOpen 2
  67. #define miFileAddImf 3
  68. #define miFileAddResources 4
  69. /* 5 */
  70. #define miFileSave 6
  71. #define miFileSaveImf 7
  72. #define miFileSaveResources 8
  73. #define miFileSelectedOnly 9
  74. /* 10 */
  75. #define miFileQuit 11
  76.  
  77. #define mEdit 130
  78.  
  79. #define miEditCut 1
  80. #define miEditCopy 2
  81. #define miEditPaste 3
  82. #define miEditClear 4
  83.  
  84. #define mView 131
  85. #define miView4x4 1
  86. #define miView8x8 2
  87. #define miView16x16 3
  88. #define miView32x32 4
  89. #define miView64x64 5
  90. /* 6 */
  91. #define miViewColor 7
  92. #define miViewNames 8
  93. #define miViewMask 9
  94. /* 10 */
  95. #define miViewAsUnit 11
  96. #define miViewAsTerrain 12
  97. #define miViewAsEmblem 13
  98. #define miViewWithUnit 14
  99. #define miViewWithTerrain 15
  100. #define miViewWithEmblem 16
  101. /* 17 */
  102. #define miViewIcons 18
  103. #define miViewTiles 19
  104. #define miViewCQD 20
  105.  
  106. #define wImages 128
  107.  
  108. #define aAbout 128
  109. #define aWarning 140
  110. #define aError 141
  111.  
  112. #define is_selected(imf) (imf == selected_imf)
  113.  
  114. /* Global variables. */
  115.  
  116. int debug_output = 1;
  117.  
  118. /* Variables tweaked by menu items. */
  119.  
  120. int write_all = 1;
  121.  
  122. int show_color = 1;
  123. int show_names = 1;
  124. int show_mask = 1;
  125.  
  126. int vary_unit = 1;
  127. int vary_terrain = 0;
  128. int vary_emblem = 0;
  129.  
  130. int with_unit = 0;
  131. int with_terrain = 0;
  132. int with_emblem = 0;
  133.  
  134. int select_icons = 1;
  135. int select_tiles = 1;
  136.  
  137. /* Pointers to the image families being held constant for display. */
  138.  
  139. ImageFamily *const_terrain = NULL;
  140.  
  141. ImageFamily *const_unit = NULL;
  142.  
  143. ImageFamily *const_emblem = NULL;
  144.  
  145. int iw = 16, ih = 16;
  146.  
  147. int hasColorQD;
  148.  
  149. int useColorQD;
  150.  
  151. int useWNE;
  152.  
  153. char spbuf[1000];
  154. char tmpbuf[1000];
  155.  
  156. Str255 tmpstr;
  157.  
  158. /* Resource ids. */
  159.  
  160. short nextimageid;
  161. short nextpatid;
  162. short nextppatid;
  163. short nextsicnid;
  164. short nexticonid;
  165. short nextcicnid;
  166. short nextcolorid;
  167. short nextimfid;
  168.  
  169. /* Pointer to storage for all the image families. */
  170.  
  171. ImageFamily *selected_imf = NULL;
  172.  
  173. int selected_n = 0;
  174.  
  175. WindowPtr imagewin = NULL;
  176.  
  177. Rect dragrect = { -32000, -32000, 32000, 32000 };
  178. Rect sizerect;
  179.  
  180. /* This variable leaves space for two lines of text at the top of the window. */
  181.  
  182. int toplineh = 32;
  183.  
  184. /* The one scrollbar. */
  185.  
  186. ControlHandle vscrollbar = nil;
  187.  
  188. Rect vscrollrect;
  189.  
  190. int sbarwid = 15;
  191.  
  192. int numvisrows = 0;
  193.  
  194. int firstvisrow = 0;
  195.  
  196. int winwidth, winheight;
  197.  
  198. /* The numbers of rows and columns of images. */
  199.  
  200. int rows, cols;
  201.  
  202. /* The size of the rectangle allocated to a single image. */
  203.  
  204. int eltw, elth;
  205.  
  206. CursHandle watchcursor;
  207.  
  208. /* Function prototypes. */
  209.  
  210. void do_event(EventRecord *event);
  211. void grow_scrollbar(void);
  212. void do_menu_command(long which);
  213. void adjust_menus(void);
  214. void clear_everything(void);
  215. pascal void scroll_proc(ControlHandle control, short code);
  216. void handle_mouse_click(Point mouse, int mods);
  217. void force_update(void);
  218.  
  219. void imf_callback(ImageFamily *imf, int loadnow);
  220.  
  221. void open_imf_dir_file(void);
  222. void open_imf_file(void);
  223. void open_resource_file(void);
  224. void collect_all_resources(ResType typ);
  225. void collect_all_colors(ResType typ);
  226.  
  227. void save_imf_dir_file(void);
  228. void save_imf_file(void);
  229. void save_resource_file(void);
  230. void make_imf_resources(ImageFamily *imf);
  231. void make_imc_resources(ImageColor *imc);
  232.  
  233. void update_image_window(void);
  234. void draw_topline(void);
  235. void draw_one_image(ImageFamily *imf, int col, int row);
  236. void set_scrollbar(void);
  237. void invert_selected_imf(void);
  238. void draw_as_terrain_image(int sx, int sy, int sw, int sh, ImageFamily *imf);
  239. void draw_as_unit_image(WindowPtr win, int sx, int sy, int sw, int sh, ImageFamily *imf);
  240. void draw_as_emblem_image(WindowPtr win, int ex, int ey, int ew, int eh, ImageFamily *imf);
  241.  
  242. char *copy_pascal_string(char *str);
  243.  
  244. /* The program proper. */
  245.  
  246. int
  247. main()
  248. {
  249.     SysEnvRec se;
  250.     Handle menubar;
  251.     MenuHandle menu;
  252.     RgnHandle cursorrgn;
  253.     Boolean gotevent;
  254.     EventRecord    event;
  255.  
  256.     InitGraf(&QD(thePort));
  257.     InitFonts();
  258.     FlushEvents(everyEvent, 0);
  259.     InitWindows();
  260.     InitMenus();
  261.     TEInit();
  262.     InitDialogs(NULL);
  263.     InitCursor();
  264.     watchcursor = GetCursor(watchCursor);
  265.  
  266.     SysEnvirons(2, &se);
  267.     hasColorQD = se.hasColorQD;
  268.     useColorQD = hasColorQD;
  269.     /* Set up the menu bar.  No trickery needed. */
  270.     menubar = GetNewMBar(mbMain);
  271.     SetMenuBar(menubar);
  272.     /* Add the DAs etc as usual. */
  273.     menu = GetMHandle(mApple);
  274.     if (menu != nil) {
  275.         AddResMenu(menu, 'DRVR');
  276.     }
  277.     DrawMenuBar();
  278.  
  279.     init_lisp();
  280.  
  281.     /* Create the main window we're going to play in. */
  282.     if (hasColorQD) {
  283.         imagewin = GetNewCWindow(wImages, NULL, (WindowPtr) -1L);
  284.     } else {
  285.         imagewin = GetNewWindow(wImages, NULL, (WindowPtr) -1L);
  286.     }
  287.     vscrollrect = imagewin->portRect;
  288.     vscrollrect.left = vscrollrect.right - sbarwid;  vscrollrect.top += toplineh - 1;
  289.     vscrollrect.right += 1;  vscrollrect.bottom -= sbarwid - 1;
  290.     vscrollbar =
  291.         NewControl(imagewin, &vscrollrect, "\p", 1, 0, 0, 100, scrollBarProc, 0L);
  292.     ShowWindow(imagewin);
  293.  
  294.     sizerect.top = 50;
  295.     sizerect.left = 50;
  296.     sizerect.bottom = QD(screenBits).bounds.bottom - QD(screenBits).bounds.top;
  297.     sizerect.right  = QD(screenBits).bounds.right  - QD(screenBits).bounds.left;
  298.  
  299.     useWNE = (NGetTrapAddress(0x60, ToolTrap) != NGetTrapAddress(0x9f, ToolTrap));
  300.     /* Pass WNE an empty region the 1st time thru. */
  301.     cursorrgn = NewRgn();
  302.     while (1) {
  303.         /* Use WaitNextEvent if it is available. */
  304.         if (useWNE) {
  305.             gotevent = WaitNextEvent(everyEvent, &event, 0L, cursorrgn);
  306.         } else {
  307.             SystemTask();
  308.             gotevent = GetNextEvent(everyEvent, &event);
  309.         }
  310.         if (gotevent) {
  311.             do_event(&event);
  312.         }
  313.     }
  314.     return 0;
  315. }
  316.  
  317. /* Given an event, figure out what to do with it. */
  318.  
  319. void
  320. do_event(event)
  321. EventRecord *event;
  322. {
  323.     short part, err;
  324.     WindowPtr window;
  325.     char key;
  326.     Point pnt;
  327.     long winsize;
  328.     GrafPtr oldport;
  329.  
  330.     switch (event->what) {
  331.         case mouseDown:
  332.             part = FindWindow(event->where, &window);
  333.             switch (part) {
  334.                 case inMenuBar:
  335.                     adjust_menus();
  336.                     do_menu_command(MenuSelect(event->where));
  337.                     break;
  338.                 case inSysWindow:
  339.                     SystemClick(event, window);
  340.                     break;
  341.                 case inContent:
  342.                     if (window != FrontWindow()) {
  343.                         SelectWindow(window);
  344.                         /* We just want to discard the event, since clicks in a
  345.                            windows are sometimes irreversible actions. */
  346.                         adjust_menus();
  347.                     } else {
  348.                         handle_mouse_click(event->where, event->modifiers);
  349.                     }
  350.                     break;
  351.                 case inDrag:
  352.                     DragWindow(window, event->where, &dragrect);
  353.                     break;
  354.                 case inGrow:
  355.                     winsize = GrowWindow(window, event->where, &sizerect);
  356.                     if (winsize != 0) {
  357.                         GetPort(&oldport);
  358.                         SetPort(window);
  359.                         EraseRect(&window->portRect);
  360.                         SizeWindow(window, LoWord(winsize), HiWord(winsize), 1);
  361.                         grow_scrollbar();
  362.                         InvalRect(&window->portRect);
  363.                         SetPort(oldport);
  364.                     }
  365.                     break;
  366.                 case inZoomIn:
  367.                 case inZoomOut:
  368.                     if (TrackBox(window, event->where, part)) {
  369.                         GetPort(&oldport);
  370.                         /* The window must be the current port. (ZoomWindow bug) */
  371.                         SetPort(window);
  372.                         EraseRect(&window->portRect);
  373.                         ZoomWindow(window, part, true);
  374.                         grow_scrollbar();
  375.                         InvalRect(&window->portRect);
  376.                         SetPort(oldport);
  377.                     }
  378.                     break;
  379.                 case inGoAway:
  380.                     /* Don't mess around, just shut down. */
  381.                     ExitToShell();
  382.                     break;
  383.             }
  384.             break;
  385.         case mouseUp:
  386.             part = FindWindow(event->where, &window);
  387.             switch (part) {
  388.                 case inContent:
  389.                     if (0 /* up in diff window than down? */) {
  390.                     } else {
  391.                     }
  392.                     break;
  393.             }
  394.             break;
  395.         case keyDown:
  396.         case autoKey:
  397.             key = event->message & charCodeMask;
  398.             /* Check for menukey equivalents. */
  399.             if (event->modifiers & cmdKey) {
  400.                 if (event->what == keyDown) {
  401.                     adjust_menus();
  402.                     do_menu_command(MenuKey(key));
  403.                 }
  404.             } else {
  405.                 if (event->what == keyDown) {
  406.                     /* Random keypress, interpret it. */
  407.                 }
  408.             }
  409.             break;
  410.         case activateEvt:
  411.             break;
  412.         case updateEvt:
  413.             if (imagewin == ((WindowPtr) event->message)) {
  414.                 update_image_window();
  415.             }
  416.             break;
  417.         case diskEvt:
  418.             /*    Call DIBadMount in response to a diskEvt, so that the user can format
  419.                  a floppy. (from DTS Sample) */
  420.             if (HiWord(event->message) != noErr) {
  421.                 SetPt(&pnt, 50, 50);
  422.                 err = DIBadMount(pnt, event->message);
  423.             }
  424.             break;
  425. #if 0
  426.         case kOSEvent:
  427.         /*    1.02 - must BitAND with 0x0FF to get only low byte */
  428.             switch ((event->message >> 24) & 0x0FF) {        /* high byte of message */
  429.                 case kSuspendResumeMessage:        /* suspend/resume is also an activate/deactivate */
  430.                     gInBackground = (event->message & kResumeMask) == 0;
  431.                     DoActivate(FrontWindow(), !gInBackground);
  432.                     break;
  433.             }
  434.             break;
  435. #endif
  436.         default:
  437.             break;
  438.     }
  439. }
  440.  
  441. void
  442. grow_scrollbar()
  443. {
  444.     Rect tmprect = imagewin->portRect;
  445.  
  446.     MoveControl(vscrollbar, tmprect.right - sbarwid, toplineh - 1);
  447.     SizeControl(vscrollbar, sbarwid + 1, tmprect.bottom - tmprect.top - toplineh - sbarwid + 1 + 1);
  448. }
  449.  
  450. /* Decipher and do a menu command. */
  451.  
  452. void
  453. do_menu_command(which)
  454. long which;
  455. {
  456.     short menuid, menuitem;
  457.     Str255 daname;
  458.     short darefnum;
  459.  
  460.     menuid = HiWord(which);
  461.     menuitem = LoWord(which);
  462.     switch (menuid) {
  463.         case mApple:
  464.             switch (menuitem) {
  465.                 case miAbout:
  466.                     Alert(aAbout, nil);
  467.                     break;
  468.                 default:
  469.                     GetItem(GetMHandle(mApple), menuitem, daname);
  470.                     darefnum = OpenDeskAcc(daname);
  471.             }
  472.             break;
  473.         case mFile:
  474.             switch (menuitem) {
  475.                 case miFileNew:
  476.                     clear_everything();
  477.                     /* Clean up the display (should not be necessary though). */
  478.                     force_update();
  479.                     break;
  480.                 case miFileOpen:
  481.                     open_imf_dir_file();
  482.                     /* Clean up the display (should not be necessary though). */
  483.                     force_update();
  484.                     break;
  485.                 case miFileAddImf:
  486.                     open_imf_file();
  487.                     /* Clean up the display (should not be necessary though). */
  488.                     force_update();
  489.                     break;
  490.                 case miFileAddResources:
  491.                     open_resource_file();
  492.                     /* Clean up the display (should not be necessary though). */
  493.                     force_update();
  494.                     break;
  495.                 case miFileSave:
  496.                     save_imf_dir_file();
  497.                     break;
  498.                 case miFileSaveImf:
  499.                     save_imf_file();
  500.                     break;
  501.                 case miFileSaveResources:
  502.                     save_resource_file();
  503.                     break;
  504.                 case miFileSelectedOnly:
  505.                     write_all = !write_all;
  506.                     break;
  507.                 case miFileQuit:
  508.                     ExitToShell();
  509.                     break;
  510.             }
  511.             break;
  512.         case mEdit:
  513.             /* handledbyda = SystemEdit(menuitem-1); */
  514.             switch (menuitem)  {
  515.                 case miEditCut:
  516.                     break;
  517.                 case miEditCopy:
  518.                     break;
  519.                 case miEditPaste:
  520.                     break;
  521.                 case miEditClear:
  522.                     break;
  523.             }
  524.             break;
  525.         case mView:
  526.             switch (menuitem) {
  527.                 case miView4x4:
  528.                     iw = ih = 4;
  529.                     break;
  530.                 case miView8x8:
  531.                     iw = ih = 8;
  532.                     break;
  533.                 case miView16x16:
  534.                     iw = ih = 16;
  535.                     break;
  536.                 case miView32x32:
  537.                     iw = ih = 32;
  538.                     break;
  539.                 case miView64x64:
  540.                     iw = ih = 64;
  541.                     break;
  542.                 case miViewColor:
  543.                     show_color = !show_color;
  544.                     break;
  545.                 case miViewNames:
  546.                     show_names = !show_names;
  547.                     break;
  548.                 case miViewMask:
  549.                     show_mask = !show_mask;
  550.                     break;
  551.                 case miViewAsUnit:
  552.                     vary_unit = 1;
  553.                     vary_terrain = 0;
  554.                     vary_emblem = 0;
  555.                     break;
  556.                 case miViewAsTerrain:
  557.                     vary_unit = 0;
  558.                     vary_terrain = 1;
  559.                     vary_emblem = 0;
  560.                     break;
  561.                 case miViewAsEmblem:
  562.                     vary_unit = 0;
  563.                     vary_terrain = 0;
  564.                     vary_emblem = 1;
  565.                     break;
  566.                 case miViewWithUnit:
  567.                     with_unit = !with_unit;
  568.                     const_unit = selected_imf;
  569.                     break;
  570.                 case miViewWithTerrain:
  571.                     with_terrain = !with_terrain;
  572.                     const_terrain = selected_imf;
  573.                     break;
  574.                 case miViewWithEmblem:
  575.                     with_emblem = !with_emblem;
  576.                     const_emblem = selected_imf;
  577.                     break;
  578.                 case miViewIcons:
  579.                     select_icons = !select_icons;
  580.                     break;
  581.                 case miViewTiles:
  582.                     select_tiles = !select_tiles;
  583.                     break;
  584.                 case miViewCQD:
  585.                     useColorQD = !useColorQD;
  586.                     break;
  587.             }
  588.             force_update();
  589.             break;
  590.     }
  591.     HiliteMenu(0);
  592. }
  593.  
  594. /* Set enabling and decoration of menus to reflect current state. */
  595.  
  596. void
  597. adjust_menus()
  598. {
  599.     MenuHandle menu;
  600.  
  601.     if ((menu = GetMHandle(mFile)) != nil) {
  602.         CheckItem(menu, miFileSelectedOnly, !write_all);
  603.     }
  604.     if ((menu = GetMHandle(mView)) != nil) {
  605.         CheckItem(menu, miView4x4, (iw == 4));
  606.         CheckItem(menu, miView8x8, (iw == 8));
  607.         CheckItem(menu, miView16x16, (iw == 16));
  608.         CheckItem(menu, miView32x32, (iw == 32));
  609.         CheckItem(menu, miView64x64, (iw == 64));
  610.         if (hasColorQD) {
  611.             EnableItem(menu, miViewColor);
  612.             CheckItem(menu, miViewColor, show_color);
  613.             EnableItem(menu, miViewCQD);
  614.             CheckItem(menu, miViewCQD, useColorQD);
  615.         } else {
  616.             DisableItem(menu, miViewColor);
  617.             DisableItem(menu, miViewCQD);
  618.         }
  619.         CheckItem(menu, miViewNames, show_names);
  620.         CheckItem(menu, miViewMask, show_mask);
  621.         CheckItem(menu, miViewAsUnit, vary_unit);
  622.         CheckItem(menu, miViewAsTerrain, vary_terrain);
  623.         CheckItem(menu, miViewAsEmblem, vary_emblem);
  624.         CheckItem(menu, miViewWithUnit, with_unit);
  625.         if ((selected_imf != NULL && !vary_unit) || with_unit) {
  626.             EnableItem(menu, miViewWithUnit);
  627.         } else {
  628.             DisableItem(menu, miViewWithUnit);
  629.         }
  630.         CheckItem(menu, miViewWithTerrain, with_terrain);
  631.         if ((selected_imf != NULL && !vary_terrain) || with_terrain) {
  632.             EnableItem(menu, miViewWithTerrain);
  633.         } else {
  634.             DisableItem(menu, miViewWithTerrain);
  635.         }
  636.         CheckItem(menu, miViewWithEmblem, with_emblem);
  637.         if ((selected_imf != NULL && !vary_emblem) || with_emblem) {
  638.             EnableItem(menu, miViewWithEmblem);
  639.         } else {
  640.             DisableItem(menu, miViewWithEmblem);
  641.         }
  642.         CheckItem(menu, miViewIcons, select_icons);
  643.         CheckItem(menu, miViewTiles, select_tiles);
  644.         CheckItem(menu, miViewCQD, useColorQD);
  645.     }
  646. }
  647.  
  648. /* Empty all data, files, etc. */
  649.  
  650. void
  651. clear_everything()
  652. {
  653.     numimages = 0;
  654.     numcolors = 0;
  655.  
  656.     selected_imf = NULL;
  657.     selected_n = 0;
  658.     const_terrain = NULL;
  659.     const_unit = NULL;
  660.     const_emblem = NULL;
  661.     numvisrows = firstvisrow = 0;
  662. }
  663.  
  664. pascal void
  665. scroll_proc(control, code)
  666. ControlHandle control;
  667. short code;
  668. {
  669.     int curvalue, jump;
  670.  
  671.     curvalue = GetCtlValue(control);
  672.     switch (code) {
  673.         case inPageDown:
  674.             jump = (numvisrows > 2 ? numvisrows - 2 : 1);
  675.             break;
  676.         case inDownButton:
  677.             jump = 1;
  678.             break;
  679.         case inPageUp:
  680.             jump = - (numvisrows > 2 ? numvisrows - 2 : 1);
  681.             break;
  682.         case inUpButton:
  683.             jump = -1;
  684.             break;
  685.         default:
  686.             jump = 0;
  687.             break;
  688.     }
  689.     curvalue += jump;
  690.     SetCtlValue(control, curvalue);
  691. }
  692.  
  693. void
  694. handle_mouse_click(mouse, mods)
  695. Point mouse;
  696. int mods;
  697. {
  698.     int row, col, n;
  699.     ControlHandle control;
  700.     short part, oldvalue;
  701.  
  702.     SetPort(imagewin);
  703.     GlobalToLocal(&mouse);
  704.     part = FindControl(mouse, imagewin, &control);
  705.     if (control == vscrollbar) {
  706.         oldvalue = GetCtlValue(vscrollbar);
  707.         switch (part) {
  708.             case inThumb:
  709.                 part = TrackControl(control, mouse, NULL);
  710.                 break;
  711.             default:
  712.                 part = TrackControl(control, mouse, (ProcPtr) scroll_proc);
  713.                 break;
  714.         }
  715.         firstvisrow = GetCtlValue(vscrollbar);
  716.         if (oldvalue != firstvisrow) {
  717.             force_update();
  718.         }
  719.     } else if (mouse.v <= toplineh) {
  720.         /* Clicking in the topline area de-selects always. */
  721.         invert_selected_imf();
  722.         selected_imf = NULL;
  723.         draw_topline();
  724.     } else {
  725.         /* Figure out which image was clicked on. */
  726.         col = mouse.h / eltw;
  727.         row = (mouse.v - toplineh) / elth + firstvisrow;
  728.         n = row * cols + col;
  729.         if (n >= 0 && n < numimages) {
  730.             if (!is_selected(images[n])) {
  731.                 invert_selected_imf();
  732.                 selected_imf = images[n];
  733.                 selected_n = n;
  734.                 invert_selected_imf();
  735.             }
  736.             if (mods & cmdKey) {
  737.                 with_terrain = 1;
  738.                 const_terrain = selected_imf;
  739.                 force_update();
  740.             }
  741.             if (mods & optionKey) {
  742.                 with_emblem = 1;
  743.                 const_emblem = selected_imf;
  744.                 force_update();
  745.             }
  746.         } else {
  747.             invert_selected_imf();
  748.             selected_imf = NULL;
  749.         }
  750.         draw_topline();
  751.     }
  752. }
  753.  
  754. void
  755. force_update()
  756. {
  757.     GrafPtr oldport;
  758.  
  759.     GetPort(&oldport);
  760.     SetPort(imagewin);
  761.     EraseRect(&imagewin->portRect);
  762.     InvalRect(&imagewin->portRect);
  763.     SetPort(oldport);
  764. }
  765.  
  766. /* INPUT/OUTPUT */
  767.  
  768. void
  769. imf_callback(imf, loadnow)
  770. ImageFamily *imf;
  771. int loadnow;
  772. {
  773.     if (loadnow && imf != NULL)
  774.       mac_interp_imf(imf);
  775.     /* Do some visual feedback periodically. */
  776.     if (numimages % 10 == 0)
  777.       draw_topline();
  778. }
  779.  
  780. void
  781. open_imf_dir_file()
  782. {
  783.     char filename[BUFSIZE];
  784.     int startlineno = 0, endlineno = 0;
  785.     FILE *fp;
  786.     Point pnt;
  787.     SFTypeList typelist;
  788.     SFReply reply;
  789.  
  790.     /* Gotta be somewhere... */
  791.     SetPt(&pnt, 100, 100);
  792.     /* Only read text files. */
  793.     typelist[0] = 'TEXT';
  794.     SFGetFile(pnt, "\p", NULL, 1, typelist, NULL, &reply);
  795.     if (reply.good) {
  796.         /* Make the location of the file be the current volume. */
  797.         SetVol(reply.fName, reply.vRefNum);
  798.         p2c(((char *) reply.fName), filename);
  799.         SetCursor(*watchcursor);
  800.         fp = fopen(filename, "r");
  801.         if (fp != NULL) {
  802.             load_image_families(fp, TRUE, imf_callback);
  803.             fclose(fp);
  804.         }
  805.         /* Sort all into alphabetical order. */
  806.         sort_all_images();
  807.         sort_all_colors();
  808.         SetCursor(&QD(arrow));
  809.     }
  810. }
  811.  
  812. /* Open and read/interpret the contents of an imf file. */
  813.  
  814. void
  815. open_imf_file()
  816. {
  817.     char filename[BUFSIZE];
  818.     Point pnt;
  819.     SFTypeList typelist;
  820.     SFReply reply;
  821.  
  822.     /* Gotta be somewhere... */
  823.     SetPt(&pnt, 100, 100);
  824.     /* Only read text files. */
  825.     typelist[0] = 'TEXT';
  826.     SFGetFile(pnt, "\p", NULL, 1, typelist, NULL, &reply);
  827.     if (reply.good) {
  828.         /* Make the location of the file be the current volume. */
  829.         SetVol(reply.fName, reply.vRefNum);
  830.         p2c(((char *) reply.fName), filename);
  831.         SetCursor(*watchcursor);
  832.         load_imf_file(filename, imf_callback);
  833.         /* Sort all into alphabetical order. */
  834.         sort_all_images();
  835.         sort_all_colors();
  836.         SetCursor(&QD(arrow));
  837.     }
  838. }
  839.  
  840. /* Get the name of a resource file, open it, and make image families out
  841.    of all appropriate resource types. */
  842.  
  843. void
  844. open_resource_file()
  845. {
  846.     Point pnt;
  847.     SFTypeList typelist;
  848.     SFReply reply;
  849.  
  850.     /* Gotta be somewhere... */
  851.     SetPt(&pnt, 100, 100);
  852.     /* Pick up any sort of file. */
  853.     SFGetFile(pnt, "\p", NULL, -1, typelist, NULL, &reply);
  854.     if (reply.good) {
  855.         SetVol(reply.fName, reply.vRefNum);
  856.         SetCursor(*watchcursor);
  857.         if (OpenResFile(reply.fName) != -1) {
  858.             /* Now that all the resources are available, go through all types of rsrcs
  859.                that might have useful images. */
  860.             collect_all_resources('XCif');
  861.             collect_all_resources('cicn');
  862.             collect_all_resources('ICON');
  863.             collect_all_resources('SICN');
  864.             collect_all_resources('ppat');
  865.             collect_all_resources('PAT ');
  866.             collect_all_colors('XCic');
  867.             /* Sort all into alphabetical order. */
  868.             sort_all_images();
  869.             sort_all_colors();
  870.         } else {
  871.             init_warning("could not open resource file");
  872.         }
  873.         SetCursor(&QD(arrow));
  874.     }
  875. }
  876.  
  877. /* Given a resource type, get image families for all resources of that type. */
  878.  
  879. void
  880. collect_all_resources(ResType typ)
  881. {
  882.     int i, n, len;
  883.     char *imfname;
  884.     ImageFamily *imf;
  885.     Handle handle;
  886.     short resid;  ResType restype;  Str255 resname;
  887.  
  888.     n = CountResources(typ);
  889.     for (i = 0; i < n; ++i ) {
  890.         imfname = NULL;
  891.         handle = GetIndResource(typ, i + 1);
  892.         GetResInfo(handle, &resid, &restype, resname);
  893.         if (resname[0] > 0) {
  894.             imfname = copy_pascal_string((char *) resname);
  895.         } else {
  896.             /* (should synth names for unnamed resources) */
  897.         }
  898.         len = strlen(imfname);
  899.         if (imfname != NULL
  900.             /* Resources with names ending in " mask" are masks for other resources,
  901.                so ignore them here. */
  902.             && strcmp(imfname + len - 5, " mask") != 0) {
  903.             /* Peel off size specs if present. */
  904.             if (strcmp(imfname + len - 4, " 8x8") == 0) {
  905.                 /* String is a copy, so we can do this. */
  906.                 imfname[len - 4] = '\0';
  907.             }
  908.             if (strcmp(imfname + len - 6, " 16x16") == 0
  909.                 || strcmp(imfname + len - 6, " 32x32") == 0) {
  910.                 /* String is a copy, so we can do this. */
  911.                 imfname[len - 6] = '\0';
  912.             }
  913.             imf = get_imf(imfname);
  914.             mac_load_imf(imf);
  915.             make_generic_image_data(imf);
  916.             check_imf(imf);
  917.             /* Do some visual feedback periodically. */
  918.             if (numimages % 10 == 0)
  919.               draw_topline();
  920.         }
  921.     }
  922. }
  923.  
  924. /* Given a resource type, get named colors for all resources of that type. */
  925.  
  926. void
  927. collect_all_colors(ResType typ)
  928. {
  929.     int i, n;
  930.     char *imcname;
  931.     ImageColor *imc;
  932.     Handle handle;
  933.     short resid;  ResType restype;  Str255 resname;
  934.  
  935.     n = CountResources(typ);
  936.     for (i = 0; i < n; ++i ) {
  937.         imcname = NULL;
  938.         handle = GetIndResource(typ, i + 1);
  939.         GetResInfo(handle, &resid, &restype, resname);
  940.         if (resname[0] > 0) {
  941.             imcname = copy_pascal_string((char *) resname);
  942.         } else {
  943.             /* (should synth names for unnamed resources) */
  944.         }
  945.         if (imcname != NULL) {
  946.             imc = get_imc(imcname);
  947.             mac_load_image_color(imc);
  948.             /* Do some visual feedback periodically. */
  949.             if (numcolors % 10 == 0)
  950.               draw_topline();
  951.         }
  952.     }
  953. }
  954.  
  955. void
  956. save_imf_dir_file()
  957. {
  958.     int i;
  959.     char filename[BUFSIZE], *loc;
  960.     Point pnt;
  961.     FILE *fp;
  962.     SFReply reply;
  963.     ImageFamily *imf;
  964.  
  965.     SetPt(&pnt, 100, 100);
  966.     SFPutFile(pnt, "\p", "\pimf.dir", nil, &reply);
  967.     if (reply.good) {
  968.         /* Make the location of the file be the current volume. */
  969.         SetVol(reply.fName, reply.vRefNum);
  970.         p2c(((char *) reply.fName), filename);
  971.         SetCursor(*watchcursor);
  972.         /* (should genericize into a write_imf_dir that takes array of images) */
  973.         fp = fopen(filename, "w");
  974.         if (fp != NULL) {
  975.             fprintf(fp, "ImageFamilyName FileName\n");
  976.             for (i = 0; i < numimages; ++i) {
  977.                 imf = images[i];
  978.                 if (write_all || is_selected(imf)) {
  979.                     loc = "???";
  980.                     if (imf->location && !empty_string(imf->location->name))
  981.                       loc = imf->location->name;
  982.                     fprintf(fp, "%s %s\n", imf->name, loc);
  983.                 }
  984.                 /* (to write imf files, should scan through images once for
  985.                     each file, writing all images found that are in that file) */
  986.             }
  987.             fprintf(fp, ". .\n");
  988.             fclose(fp);
  989.         } else {
  990.             run_warning("could not open file for writing");
  991.         }
  992.         SetCursor(&QD(arrow));
  993.     }
  994. }
  995.  
  996. /* Write all the images into an imf file. */
  997.  
  998. void
  999. save_imf_file()
  1000. {
  1001.     int i;
  1002.     char filename[BUFSIZE];
  1003.     Point pnt;
  1004.     FILE *fp;
  1005.     SFReply reply;
  1006.  
  1007.     SetPt(&pnt, 100, 100);
  1008.     SFPutFile(pnt, "\p", "\pimages.imf", nil, &reply);
  1009.     if (reply.good) {
  1010.         /* Make the location of the file be the current volume. */
  1011.         SetVol(reply.fName, reply.vRefNum);
  1012.         p2c(((char *) reply.fName), filename);
  1013.         SetCursor(*watchcursor);
  1014.         fp = fopen(filename, "w");
  1015.         if (fp != NULL) {
  1016.             /* Write out the imf forms of all the image families. */
  1017.             for (i = 0; i < numimages; ++i) {
  1018.                 if (write_all || is_selected(images[i])) {
  1019.                     make_generic_image_data(images[i]);
  1020.                     write_imf(fp, images[i]);
  1021.                 }
  1022.             }
  1023.             /* Write out the image colors. */
  1024.             for (i = 0; i < numcolors; ++i) {
  1025.                 if (write_all) {  /* (should have a way to select colors) */
  1026.                     write_imc(fp, colors[i]);
  1027.                 }
  1028.             }
  1029.             fclose(fp);
  1030.         } else {
  1031.             run_warning("could not open file for writing");
  1032.         }
  1033.         SetCursor(&QD(arrow));
  1034.     }
  1035. }
  1036.  
  1037. /* Write all the images, as resources, into a resource file. */
  1038.  
  1039. void
  1040. save_resource_file()
  1041. {
  1042.     int refnum, i;
  1043.     Point pnt;
  1044.     SFReply reply;
  1045.  
  1046.     SetPt(&pnt, 100, 100);
  1047.     SFPutFile(pnt, "\p", "\pimages.imf Images", nil, &reply);
  1048.     if (reply.good) {
  1049.         /* Make the location of the file be the current volume. */
  1050.         SetVol(reply.fName, reply.vRefNum);
  1051.         SetCursor(*watchcursor);
  1052.         CreateResFile(reply.fName);
  1053.         refnum = OpenResFile(reply.fName);
  1054.         if (refnum >= 0) {
  1055.             /* All synthesized resource ids should go from 1000 up. */
  1056.             nextpatid = 1000;
  1057.             nextppatid = 1000;
  1058.             nextsicnid = 1000;
  1059.             nexticonid = 1000;
  1060.             nextcicnid = 1000;
  1061.             nextcolorid = 1000;
  1062.             nextimfid = 1000;
  1063.             /* Make resources for named colors. */
  1064.             for (i = 0; i < numcolors; ++i) {
  1065.                 make_imc_resources(colors[i]);
  1066.             }
  1067.             /* Make resources for image family specifications. */
  1068.             for (i = 0; i < numimages; ++i) {
  1069.                 if (write_all || is_selected(images[i])) {
  1070.                     make_imf_resources(images[i]);
  1071.                 }
  1072.             }
  1073.             /* Closing the resource file causes actual writing. */
  1074.             CloseResFile(refnum);
  1075.         } else {
  1076.             run_warning("could not open resource file");
  1077.         }
  1078.         SetCursor(&QD(arrow));
  1079.     }
  1080. }
  1081.  
  1082. static int write_location = FALSE;
  1083.  
  1084. void
  1085. make_imf_resources(imf)
  1086. ImageFamily *imf;
  1087. {
  1088.     int j, makexcif = FALSE, needimghead;
  1089.     char buf[BUFSIZE], xcifbuf[1000];
  1090.     Handle imfhandle, handle;
  1091.     Str255 tmpstr, tmpstrmask;
  1092.     Image *img;
  1093.     MacImage *macimg;
  1094.  
  1095.     if (imf == NULL || imf->name == NULL)
  1096.       return;
  1097.     /* Make the resource names that we will use. */
  1098.     c2p(imf->name, tmpstr);
  1099.     sprintf(buf, "%s mask", imf->name);
  1100.     c2p(buf, tmpstrmask);
  1101.     sprintf(xcifbuf, "(");
  1102.     if (write_location && imf->location && imf->location->name) {
  1103.         sprintf(xcifbuf+strlen(xcifbuf), "(in \"%s\")", imf->location->name);
  1104.         makexcif = TRUE;
  1105.     }
  1106.     for (img = imf->images; img != NULL; img = img->next) {
  1107.         needimghead = 1;
  1108.         if (img->istile || img->embedname) {
  1109.             sprintf(xcifbuf+strlen(xcifbuf), " ((%d %d", img->w, img->h);
  1110.             if (img->istile)
  1111.               strcat(xcifbuf, " tile");
  1112.             strcat(xcifbuf, ")");
  1113.             needimghead = 0;
  1114.             if (img->embedname) {
  1115.                 sprintf(xcifbuf+strlen(xcifbuf), " (embed \"%s\")", img->embedname);
  1116.             }
  1117.             makexcif = TRUE;
  1118.         }
  1119.         if (!needimghead)
  1120.           strcat(xcifbuf, ")");
  1121.         macimg = get_mac_image(img);
  1122.         /* Now make Mac-specific resources for image cases that we know about. */
  1123.         if (macimg->patdefined) {
  1124.             handle = NewHandle(8);
  1125.             for (j = 0; j < 8; ++j) {
  1126.                 (*handle)[j] = macimg->monopat[j];
  1127.             }
  1128.             AddResource(handle, 'PAT ', nextpatid++, tmpstr);
  1129.         }
  1130.         if (macimg->monosicn != nil) {
  1131.             if (macimg->masksicn != nil) {
  1132.                 handle = NewHandle(64);
  1133.                 /* Add the mask as a second sicn. */
  1134.                 for (j = 0; j < 32; ++j)
  1135.                   (*handle)[j+32] = (*(macimg->masksicn))[j];
  1136.             } else {
  1137.                 handle = NewHandle(32);
  1138.             }
  1139.             for (j = 0; j < 32; ++j)
  1140.               (*handle)[j] = (*(macimg->monosicn))[j];
  1141.             AddResource(handle, 'SICN', nextsicnid++, tmpstr);
  1142.         } else if (macimg->masksicn != nil) {
  1143.             /* A weird case, but don't lose it. */
  1144.             handle = NewHandle(32);
  1145.             for (j = 0; j < 32; ++j)
  1146.               (*handle)[j] = (*(macimg->masksicn))[j];
  1147.             AddResource(handle, 'SICN', nextsicnid++, tmpstrmask);
  1148.         }
  1149.         if (macimg->monoicon != nil) {
  1150.             handle = NewHandle(128);
  1151.             for (j = 0; j < 128; ++j)
  1152.               (*handle)[j] = (*(macimg->monoicon))[j];
  1153.             AddResource(handle, 'ICON', nexticonid++, tmpstr);
  1154.         }
  1155.         if (macimg->maskicon != nil) {
  1156.             handle = NewHandle(128);
  1157.             for (j = 0; j < 128; ++j)
  1158.               (*handle)[j] = (*(macimg->maskicon))[j];
  1159.             AddResource(handle, 'ICON', nexticonid++, tmpstrmask);
  1160.         }
  1161.         if (hasColorQD && macimg->colrpat != nil) {
  1162.             int patsize, h, pixmapsize, ctabsize, i;
  1163.             char *addr;
  1164.             Rect bounds;
  1165.             PixPatHandle pixpathandle;
  1166.             PixPat tmppixpat;
  1167.             PixMapHandle pmhandle;
  1168.             PixMap tmppixmap;
  1169.             CTabHandle ctabhandle;
  1170.  
  1171.             pixpathandle = macimg->colrpat;
  1172.             pmhandle = (*pixpathandle)->patMap;
  1173.             bounds = (*pmhandle)->bounds;
  1174.             h = bounds.bottom - bounds.top;
  1175.             pixmapsize = h * ((*pmhandle)->rowBytes & 0x3fff);
  1176.             ctabhandle = (*pmhandle)->pmTable;
  1177.             ctabsize = 8 + 8 * ((*ctabhandle)->ctSize + 1);
  1178.             /* Make a copy of the pixpat and bash its pointers/handles. */
  1179.              memcpy(&tmppixpat, *(pixpathandle), sizeof(PixPat));
  1180.              tmppixpat.patMap = (PixMapHandle) (sizeof(PixPat));
  1181.              tmppixpat.patData = (Handle) (sizeof(PixPat) + sizeof(PixMap));
  1182.             tmppixpat.patXData = 0;
  1183.             tmppixpat.patXValid = -1;
  1184.             tmppixpat.patXMap = 0;
  1185.             if (macimg->patdefined) {
  1186.                 for (i = 0; i < 8; ++i)
  1187.                   ((char *) &tmppixpat.pat1Data)[i] = ((char *) &(macimg->monopat))[i];
  1188.             } else {
  1189.                 for (i = 0; i < 8; ++i)
  1190.                   ((char *) &tmppixpat.pat1Data)[i] = 0;
  1191.             }
  1192.             /* Make a copy of the pixmap and bash it. */
  1193.             memcpy(&tmppixmap, *pmhandle, sizeof(PixMap));
  1194.             tmppixmap.rowBytes |= 0x8000;
  1195.             tmppixmap.pmTable = (CTabHandle) (sizeof(PixPat) + sizeof(PixMap) + pixmapsize);
  1196.             /* Now allocate a handle for the resource and fill it in. */
  1197.             patsize = sizeof(PixPat) + sizeof(PixMap) + pixmapsize + ctabsize;
  1198.             handle = NewHandle(patsize);
  1199.             /* Fill up the handle. */
  1200.             HLock(handle);
  1201.             addr = *handle;
  1202.             memset(addr, 0, patsize);
  1203.             memcpy(addr, &tmppixpat, sizeof(PixPat));
  1204.             addr += sizeof(PixPat);
  1205.             memcpy(addr, &tmppixmap, sizeof(PixMap));
  1206.             addr += sizeof(PixMap);
  1207.             memcpy(addr, *((*pixpathandle)->patData), pixmapsize);
  1208.             addr += pixmapsize;
  1209.             memcpy(addr, *ctabhandle, ctabsize);
  1210.             HUnlock(handle);
  1211.             AddResource(handle, 'ppat', nextppatid++, tmpstr);
  1212.         }
  1213.         if (hasColorQD && macimg->colricon != nil) {
  1214.             int cicnsize, h, pixmapsize, masksize, monosize, ctabsize, zero = 0;
  1215.             char *addr;
  1216.             Rect bounds;
  1217.             CIconHandle cicnhandle;
  1218.             PixMap tmppixmap;
  1219.             BitMap tmpmaskbitmap;
  1220.             BitMap tmpmonobitmap;
  1221.             CTabHandle ctabhandle;
  1222.  
  1223.             cicnhandle = (CIconHandle) macimg->colricon;
  1224.             bounds = (*cicnhandle)->iconPMap.bounds;
  1225.             h = bounds.bottom - bounds.top;
  1226.             pixmapsize = h * ((*cicnhandle)->iconPMap.rowBytes & 0x3fff);
  1227.             ctabhandle = (*cicnhandle)->iconPMap.pmTable;
  1228.             ctabsize = 8 + 8 * ((*ctabhandle)->ctSize + 1);
  1229.             bounds = (*cicnhandle)->iconMask.bounds;
  1230.             h = bounds.bottom - bounds.top;
  1231.             masksize = h * (*cicnhandle)->iconMask.rowBytes;
  1232.             monosize = h * (*cicnhandle)->iconMask.rowBytes;
  1233.             /* Make a copy of the pixmap and bash it. */
  1234.             memcpy(&tmppixmap, &((*cicnhandle)->iconPMap), sizeof(PixMap));
  1235.             tmppixmap.baseAddr = 0;
  1236.             tmppixmap.rowBytes |= 0x8000;
  1237.             tmppixmap.pmTable = (CTabHandle) (sizeof(PixMap) + 2 * sizeof(BitMap) + 4
  1238.                        + masksize + monosize);
  1239.             /* Make a copy of the mask bitmap and bash it. */
  1240.             memcpy(&tmpmaskbitmap, &((*cicnhandle)->iconMask), sizeof(BitMap));
  1241.             tmpmaskbitmap.baseAddr = 0;
  1242.             /* Make a copy of the mono bitmap and bash it. */
  1243.             memcpy(&tmpmonobitmap, &((*cicnhandle)->iconBMap), sizeof(BitMap));
  1244.             tmpmonobitmap.baseAddr = 0;
  1245.             /* Now allocate a handle for the resource and fill it in. */
  1246.             cicnsize = sizeof(PixMap) + 2 * sizeof(BitMap) + 4
  1247.                        + masksize + monosize + ctabsize + pixmapsize;
  1248.             handle = NewHandle(cicnsize);
  1249.             /* Fill up the handle. */
  1250.             HLock(handle);
  1251.             addr = *handle;
  1252.             memset(addr, 0, cicnsize);
  1253.             memcpy(addr, &tmppixmap, sizeof(PixMap));
  1254.             addr += sizeof(PixMap);
  1255.             memcpy(addr, &tmpmaskbitmap, sizeof(BitMap));
  1256.             addr += sizeof(BitMap);
  1257.             memcpy(addr, &tmpmonobitmap, sizeof(BitMap));
  1258.             addr += sizeof(BitMap);
  1259.             memcpy(addr, &zero, 4);
  1260.             addr += 4;
  1261.             memcpy(addr, (char *) (*cicnhandle)->iconMaskData, masksize);
  1262.             addr += masksize;
  1263.             memcpy(addr, ((char *) (*cicnhandle)->iconMaskData) + masksize, monosize);
  1264.             addr += monosize;
  1265.             memcpy(addr, *ctabhandle, ctabsize);
  1266.             addr += ctabsize;
  1267.             memcpy(addr, *((*cicnhandle)->iconData), pixmapsize);
  1268.             HUnlock(handle);
  1269.             AddResource(handle, 'cicn', nextcicnid++, tmpstr);
  1270.         }
  1271.     }
  1272.     /* Close out the XCif data and make it into a resource too. */
  1273.     strcat(xcifbuf, ")");
  1274.     if (makexcif) {
  1275.         imfhandle = NewHandle(strlen(xcifbuf)+1);
  1276.         strcpy(*imfhandle, xcifbuf);
  1277.         AddResource(imfhandle, 'XCif', nextimfid++, tmpstr);
  1278.     }
  1279. }
  1280.  
  1281. void
  1282. make_imc_resources(imc)
  1283. ImageColor *imc;
  1284. {
  1285.     Handle handle;
  1286.  
  1287.     handle = NewHandle(6);
  1288.     ((short *) (*handle))[0] = imc->r;
  1289.     ((short *) (*handle))[1] = imc->g;
  1290.     ((short *) (*handle))[2] = imc->b;
  1291.     c2p(imc->name, tmpstr);
  1292.     AddResource(handle, 'XCic', nextcolorid++, tmpstr);
  1293. }
  1294.  
  1295. /* GRAPHICS */
  1296.  
  1297. /* Totally redraw the one window. */
  1298.  
  1299. void
  1300. update_image_window()
  1301. {
  1302.     int row, col, n;
  1303.     GrafPtr oldport;
  1304.  
  1305.     BeginUpdate(imagewin);
  1306.     GetPort(&oldport);
  1307.     SetPort(imagewin);
  1308.     EraseRect(&(imagewin->portRect));
  1309.     draw_topline();
  1310.     eltw = (show_names ? 100 : iw + 4);  elth = ih + 4;
  1311.     /* (should be determined by choice of app font) */
  1312.     if (elth < 10) elth = 10;
  1313.     winwidth = imagewin->portRect.right - imagewin->portRect.left;
  1314.     winheight = imagewin->portRect.bottom - imagewin->portRect.top;
  1315.     if (with_terrain && const_terrain) {
  1316.         if (best_image(const_terrain, iw, ih)->istile) {
  1317.             draw_as_terrain_image(0, toplineh,
  1318.                                   winwidth - sbarwid, winheight - toplineh - sbarwid,
  1319.                                   const_terrain);
  1320.         } else {
  1321.             /* (should draw under each unit separately) */
  1322.         }
  1323.     }
  1324.     /* Compute how many columns we can fit, rounding down but always at least 1. */
  1325.     cols = winwidth / eltw;
  1326.     if (cols <= 0) cols = 1;
  1327.     /* We can get a little wider spacing by recalculating the element width. */
  1328.     eltw = (winwidth - 10) / cols;
  1329.     rows = numimages / cols + 1;
  1330.     numvisrows = (winheight - toplineh - 15) / elth;
  1331.     if (numvisrows > rows)
  1332.       numvisrows = rows;
  1333.     if (firstvisrow + numvisrows > rows)
  1334.       firstvisrow = rows - numvisrows;
  1335.     for (row = firstvisrow; row < (firstvisrow + numvisrows); ++row) {
  1336.         for (col = 0; col < cols; ++col) {
  1337.             n = row * cols + col;
  1338.             if (n >= numimages)
  1339.               break;
  1340.             draw_one_image(images[n], col, row);
  1341.         }
  1342.     }
  1343.     invert_selected_imf();
  1344.     set_scrollbar();
  1345.     DrawControls(imagewin);
  1346.     DrawGrowIcon(imagewin);
  1347.     SetPort(oldport);
  1348.     EndUpdate(imagewin);
  1349. }
  1350.  
  1351. void
  1352. draw_topline()
  1353. {
  1354.     int first;
  1355.     Image *img;
  1356.     Rect tmprect;
  1357.     GrafPtr oldport;
  1358.  
  1359.     GetPort(&oldport);
  1360.     SetPort(imagewin);
  1361.     tmprect = imagewin->portRect;
  1362.     tmprect.bottom = tmprect.top + toplineh;
  1363.     EraseRect(&tmprect);
  1364.     TextFont(monaco);
  1365.     TextSize(9);
  1366.     sprintf(spbuf, "%d images", numimages);
  1367.     if (with_terrain && const_terrain != NULL) {
  1368.         sprintf(spbuf+strlen(spbuf), " (on %s terrain)", const_terrain->name);
  1369.     }
  1370.     if (with_emblem && const_emblem != NULL) {
  1371.         sprintf(spbuf+strlen(spbuf), " (with %s emblem)", const_emblem->name);
  1372.     }
  1373.     if (numcolors > 0) {
  1374.         sprintf(spbuf+strlen(spbuf), ", %d colors", numcolors);
  1375.     }
  1376.     c2p(spbuf, tmpstr);
  1377.     MoveTo(4, 12);
  1378.     DrawString(tmpstr);
  1379.     /* Draw a second line describing the selection. */
  1380.     if (selected_imf != NULL) {
  1381.         strcpy(spbuf, "[");
  1382.         strcat(spbuf, selected_imf->name);
  1383.         if (selected_imf->location && selected_imf->location->name)
  1384.           sprintf(spbuf+strlen(spbuf), " (in \"%s\")", selected_imf->location->name);
  1385.         switch (selected_imf->numsizes) {
  1386.             case 0:
  1387.                 strcat(spbuf, " (no images)");
  1388.                 break;
  1389.             case 1:
  1390.                 sprintf(spbuf+strlen(spbuf), " (1 size: %dx%d)",
  1391.                         selected_imf->images->w, selected_imf->images->h);
  1392.                 break;
  1393.             default:
  1394.                 sprintf(spbuf+strlen(spbuf), " (%d sizes:", selected_imf->numsizes);
  1395.                 first = TRUE;
  1396.                 for (img = selected_imf->images; img != NULL; img = img->next) {
  1397.                     if (first)
  1398.                       first = FALSE;
  1399.                     else
  1400.                       strcat(spbuf, ",");
  1401.                     sprintf(spbuf+strlen(spbuf), " %dx%d", img->w, img->h);
  1402.                 }
  1403.                 strcat(spbuf, ")");
  1404.                 break;
  1405.         }
  1406.         if (selected_imf->notes != lispnil) {
  1407.             if (stringp(selected_imf->notes)) {
  1408.                 strcat(spbuf, " ");
  1409.                 strcat(spbuf, c_string(selected_imf->notes));
  1410.             } else if (consp(selected_imf->notes)) {
  1411.                 if (stringp(car(selected_imf->notes))) {
  1412.                     strcat(spbuf, " ");
  1413.                     strcat(spbuf, c_string(car(selected_imf->notes)));
  1414.                 } else {
  1415.                     strcat(spbuf, " <notes>");
  1416.                 }
  1417.             } else {
  1418.                 strcat(spbuf, " <notes>");
  1419.             }
  1420.         }
  1421.         strcat(spbuf, "]");
  1422.         c2p(spbuf, tmpstr);
  1423.         MoveTo(4, 26);
  1424.         DrawString(tmpstr);
  1425.     }
  1426.     /* Draw a dividing line. */
  1427.     MoveTo(0, toplineh - 2);
  1428.     Line(imagewin->portRect.right, 0);
  1429.     /* Restore the existing port. */
  1430.     SetPort(oldport);
  1431. }
  1432.  
  1433. /* Draw a single imf at a given row and column. */
  1434.  
  1435. void
  1436. draw_one_image(imf, col, row)
  1437. ImageFamily *imf;
  1438. int col, row;
  1439. {
  1440.     int namex, namey;
  1441.     Rect tmprect, maskrect;
  1442.     FontInfo fontinfo;
  1443.  
  1444.     tmprect.left = col * eltw;  tmprect.top = toplineh + (row - firstvisrow) * elth;
  1445.     tmprect.right = tmprect.left + iw + 4;  tmprect.bottom = tmprect.top + ih + 4;
  1446.     InsetRect(&tmprect, 2, 2);
  1447.     /* Maybe draw the background terrain. (should be in a hex shape sometimes?) */
  1448.     if (vary_terrain) {
  1449.         draw_as_terrain_image(tmprect.left, tmprect.top, iw, ih, imf);
  1450.     } else if (with_terrain && const_terrain) {
  1451.         draw_as_terrain_image(tmprect.left-2, tmprect.top-2, iw+4, elth, const_terrain);
  1452.     }
  1453.     if (vary_unit) {
  1454.         draw_as_unit_image(imagewin, tmprect.left, tmprect.top, iw, ih, imf);
  1455.     } else if (with_unit && const_unit) {
  1456.         draw_as_unit_image(imagewin, tmprect.left, tmprect.top, iw, ih, const_unit);
  1457.     }
  1458.     /* Maybe draw an emblem. */
  1459.     if (vary_emblem) {
  1460.         draw_as_emblem_image(imagewin, tmprect.left + iw - 8, tmprect.top, 8, 8, imf);
  1461.     } else if (with_emblem && const_emblem) {
  1462.         draw_as_emblem_image(imagewin, tmprect.left + iw - 8, tmprect.top, 8, 8, const_emblem);
  1463.     }
  1464.     /* Maybe draw the name of the image. */
  1465.     if (show_names) {
  1466.         /* If nonwhite background, add a white rect for the name. */
  1467.         namex = col * eltw + iw + 4;
  1468.         namey = toplineh + (row - firstvisrow) * elth + (elth / 2) + 5;
  1469.         if (with_terrain && const_terrain) {
  1470.             GetFontInfo(&fontinfo);
  1471.             maskrect.left = namex;
  1472.             maskrect.top = namey - fontinfo.ascent;
  1473.             maskrect.right = maskrect.left + TextWidth(imf->name, 0, strlen(imf->name));
  1474.             maskrect.bottom = namey + fontinfo.descent + 1;
  1475.             FillRect(&maskrect, QD(white));
  1476.         }
  1477.         MoveTo(namex, namey);
  1478.         c2p(imf->name, tmpstr);
  1479.         DrawString(tmpstr);
  1480.     }
  1481. }
  1482.  
  1483. /* Adjust the scrollbar to reflect the size at which the images are being rendered. */
  1484.  
  1485. void
  1486. set_scrollbar()
  1487. {
  1488.     SetCtlMax(vscrollbar, rows - numvisrows);
  1489.     SetCtlValue(vscrollbar, firstvisrow);
  1490.     HiliteControl(vscrollbar, (numvisrows < rows ? 0 : 255));
  1491. }
  1492.  
  1493. /* Indicate which image is currently selected. */
  1494.  
  1495. void
  1496. invert_selected_imf()
  1497. {
  1498.     int row, col;
  1499.     Rect tmprect;
  1500.  
  1501.     if (selected_imf != NULL) {
  1502.         col = selected_n % cols;
  1503.         row = selected_n / cols;
  1504.         /* Calculate the bounding box for the selected image. */
  1505.         tmprect.left = col * eltw;  tmprect.top = toplineh + (row - firstvisrow) * elth;
  1506.         tmprect.right = tmprect.left + eltw;  tmprect.bottom = tmprect.top + elth;
  1507.         if (tmprect.top < toplineh) return;
  1508.         /* This inverts a rectangle around the selected image. */
  1509.         InvertRect(&tmprect);
  1510.         InsetRect(&tmprect, 1, 1);
  1511.         InvertRect(&tmprect);
  1512.     }
  1513. }
  1514.  
  1515. void
  1516. draw_as_terrain_image(int sx, int sy, int sw, int sh, ImageFamily *imf)
  1517. {
  1518.     Rect rect;
  1519.     Image *timg;
  1520.     MacImage *macimg;
  1521.  
  1522.     timg = best_image(imf, sw, sh);
  1523.     if (timg) {
  1524.         rect.left = sx;  rect.top = sy;
  1525.         rect.right = sx + sw;  rect.bottom = sy + sh;
  1526.         macimg = (MacImage *) timg->hook;
  1527.         if (macimg == NULL) {
  1528.             /* a serious error? */
  1529.         } else if (useColorQD && show_color && macimg->colrpat != nil) {
  1530.             FillCRect(&rect, macimg->colrpat);
  1531.         } else if (macimg->patdefined) {
  1532.             FillRect(&rect, (unsigned char *) &(macimg->monopat));
  1533.         } else {
  1534.             /* If no imagery, just leave blank, don't try to make a default image. */
  1535.         }
  1536.     }
  1537. }
  1538.  
  1539. /* This is similar (but not identical! beware!) to Xconq's main unit drawing routine,
  1540.    but it uses an arbitrary image family instead. */
  1541.  
  1542. void
  1543. draw_as_unit_image(WindowPtr win, int sx, int sy, int sw, int sh, ImageFamily *imf)
  1544. {
  1545.     Rect srcrect, imagerect;
  1546.     BitMap bm, *winbits;
  1547.     Image *uimg;
  1548.     MacImage *macimg;
  1549.  
  1550.     uimg = best_image(imf, sw, sh);
  1551.     if (uimg) {
  1552.         if ((uimg->istile ? !select_tiles : !select_icons))
  1553.           return;
  1554.         imagerect = win->portRect;
  1555.         imagerect.top += sy;  imagerect.left += sx;
  1556.         imagerect.bottom = imagerect.top + sh;  imagerect.right = imagerect.left + sw;
  1557.         winbits = &(((GrafPtr) win)->portBits);
  1558.         macimg = (MacImage *) uimg->hook;
  1559.         if (macimg == NULL) {
  1560.             /* a serious error? */
  1561.         } else if (macimg->monopict != nil) {
  1562.             DrawPicture(macimg->monopict, &imagerect);
  1563.         } else if (useColorQD && show_color && macimg->colricon != nil) {
  1564.             PlotCIcon(&imagerect, (CIconHandle) macimg->colricon);
  1565.         } else if (macimg->monoicon != nil) {
  1566.             SetRect(&srcrect, 0, 0, 32, 32);
  1567.             bm.rowBytes = 4;
  1568.             bm.bounds = srcrect;
  1569.             if (macimg->maskicon != nil && show_mask) {
  1570.                 bm.baseAddr = *(macimg->maskicon);
  1571.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  1572.             } else {
  1573.                 /* Draw unit bbox as default mask. (maybe shrink a little??) */
  1574.                 FillRect(&imagerect, QD(white));
  1575.             }
  1576.             bm.baseAddr = *(macimg->monoicon);
  1577.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  1578.         } else if (macimg->monosicn != nil) {
  1579.             SetRect(&srcrect, 0, 0, 16, 16);
  1580.             bm.rowBytes = 2;
  1581.             bm.bounds = srcrect;
  1582.             if (macimg->masksicn != nil && show_mask) {
  1583.                 bm.baseAddr = *(macimg->masksicn);
  1584.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  1585.             } else {
  1586.                 /* Draw unit bbox as default mask. (maybe shrink a little??) */
  1587.                 FillRect(&imagerect, QD(white));
  1588.             }
  1589.             bm.baseAddr = *(macimg->monosicn);
  1590.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  1591.         } else if ((useColorQD && show_color && macimg->colrpat) || macimg->patdefined) {
  1592.             draw_as_terrain_image(sx, sy, sw, sh, imf);
  1593.         } else {
  1594.             /* should never be possible? */
  1595.         }
  1596.     }
  1597. }
  1598.  
  1599. /* Draw a given side's emblem. Uses the current GrafPort. */
  1600.  
  1601. void
  1602. draw_as_emblem_image(WindowPtr win, int ex, int ey, int ew, int eh, ImageFamily *imf)
  1603. {
  1604.     Rect srcrect, imagerect;
  1605.     BitMap bm, *winbits;
  1606.     Image *eimg;
  1607.     MacImage *macimg;
  1608.  
  1609.     eimg = best_image(imf, ew, eh);
  1610.     /* If an image is present, display it, otherwise just suppress. */
  1611.     if (eimg) {
  1612.         if ((eimg->istile ? !select_tiles : !select_icons))
  1613.           return;
  1614.         imagerect = win->portRect;
  1615.         imagerect.top += ey;  imagerect.left += ex;
  1616.         imagerect.bottom = imagerect.top + eh;  imagerect.right = imagerect.left + ew;
  1617.         winbits = &(((GrafPtr) win)->portBits);
  1618.         macimg = (MacImage *) eimg->hook;
  1619.         if (macimg == NULL) {
  1620.             /* a serious error? */
  1621.         } else if (macimg->monopict != nil) {
  1622.             DrawPicture(macimg->monopict, &imagerect);
  1623.         } else if (useColorQD && show_color && macimg->colricon != nil) {
  1624.             PlotCIcon(&imagerect, (CIconHandle) macimg->colricon);
  1625.         } else if (macimg->monoicon != nil) {
  1626.             SetRect(&srcrect, 0, 0, 32, 32);
  1627.             bm.rowBytes = 4;
  1628.             bm.bounds = srcrect;
  1629.             if (macimg->maskicon != nil && show_mask) {
  1630.                 bm.baseAddr = *(macimg->maskicon);
  1631.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  1632.             } else {
  1633.                 /* Draw unit bbox as default mask. (maybe shrink a little??) */
  1634.                 FillRect(&imagerect, QD(white));
  1635.             }
  1636.             bm.baseAddr = *(macimg->monoicon);
  1637.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  1638.         } else if (macimg->monosicn != nil) {
  1639.             SetRect(&srcrect, 0, 0, 16, 16);
  1640.             bm.rowBytes = 2;
  1641.             bm.bounds = srcrect;
  1642.             if (macimg->masksicn != nil && show_mask) {
  1643.                 bm.baseAddr = *(macimg->masksicn);
  1644.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  1645.             } else {
  1646.                 /* Draw unit bbox as default mask. (maybe shrink a little??) */
  1647.                 FillRect(&imagerect, QD(white));
  1648.             }
  1649.             bm.baseAddr = *(macimg->monosicn);
  1650.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  1651.         } else {
  1652.             /* should never be possible? */
  1653.         }
  1654.     }
  1655. }
  1656.  
  1657. /* Lisp reader support. */
  1658.  
  1659. void
  1660. announce_read_progress()
  1661. {
  1662. }
  1663.  
  1664. char *
  1665. copy_pascal_string(char *str)
  1666. {
  1667.     int len = str[0];
  1668.     char *rslt;
  1669.  
  1670.     rslt = (char *) xmalloc(len + 1);
  1671.     strncpy(rslt, str+1, len);
  1672.     rslt[len] = '\0';
  1673.     return rslt;
  1674. }
  1675.  
  1676. void
  1677. low_init_warning(str)
  1678. char *str;
  1679. {
  1680.     /* Cursor may be weird from loading, reset it. */
  1681.     SetCursor(&QD(arrow));
  1682.     c2p(str, tmpstr);
  1683.     ParamText(tmpstr, "\p", "\p", "\p");
  1684.     switch (CautionAlert(aWarning, nil)) {
  1685.         case 1:
  1686.             /* Just keep going, hope that the warning was a false alarm. */
  1687.             /* (if option key on, should suppress future warnings) */
  1688.             break;
  1689.         default:
  1690.             ExitToShell();
  1691.             break;
  1692.     }
  1693. }
  1694.  
  1695. /* An error is immediately fatal, no recourse. */
  1696.  
  1697. void
  1698. low_init_error(str)
  1699. char *str;
  1700. {
  1701.     /* Cursor may be weird from loading, reset it. */
  1702.     SetCursor(&QD(arrow));
  1703.     c2p(str, tmpstr);
  1704.     ParamText(tmpstr, "\p", "\p", "\p");
  1705.     StopAlert(aError, nil);
  1706.     ExitToShell();
  1707. }
  1708.  
  1709. /* Map these to init_ versions, no "running" in this program. */
  1710.  
  1711. void
  1712. low_run_warning(str)
  1713. char *str;
  1714. {
  1715.     low_init_warning(str);
  1716. }
  1717.  
  1718. void
  1719. low_run_error(str)
  1720. char *str;
  1721. {
  1722.     low_init_error(str);
  1723. }
  1724.  
  1725. int
  1726. keyword_code(char *str)
  1727. {
  1728.     run_warning("fake keyword_code being called");
  1729.     return 0;
  1730. }
  1731.  
  1732. /* Make the table so keyword lookup works. */
  1733.  
  1734. struct a_key {
  1735.     char *name;
  1736. } keywordtable[] = {
  1737.  
  1738. #undef  DEF_KWD
  1739. #define DEF_KWD(NAME,code)  { NAME },
  1740.  
  1741. #include "keyword.def"
  1742.  
  1743.     { NULL }
  1744. };
  1745.  
  1746. char *
  1747. keyword_name(enum keywords k)
  1748. {
  1749.     return keywordtable[k].name;
  1750. }
  1751.  
  1752. /* Fake definitions of unneeded routines called by lisp.c. */
  1753.  
  1754. void
  1755. init_predefined_symbols()
  1756. {
  1757. }
  1758.  
  1759. int
  1760. lazy_bind(Obj *sym)
  1761. {
  1762.     return 0;
  1763. }
  1764.  
  1765. void
  1766. prealloc_debug()
  1767. {
  1768. }
  1769.  
  1770.  
  1771.